import { createDefaultOption, DBType, LogType, SAEvents, SiteAnalysisOption } from 'model/siteAnalysis.model';
import { guid, IS_LOCAL } from './utils/utils'
import * as Package from '../package.json'
import * as EventEmitter from 'events';
import { interval, Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import Worker from "./utils/server.worker.js";
import { print } from './utils/print'

import { crudFromTable, DROP_TABLE, INIT_LOG_TABLE_WEBSQL } from 'utils/websql';
import { ADD_ITEM_DB, DEL_ITEM_BYID, GET_ALL_ITEM, INIT_LOG_TABLE_DB, OPEN_DB_AND_INIT } from 'utils/indexDB';
const { version } = Package
const SINGLE_NAME = 'jxstjh_siteAnalysis'
declare const window: any;
type IsUpload = 0 | 1 // 0未上传 1已上传
export class LogItem {
    id: string;
    url: string;
    creater_date: number;
    count: number;
    constructor(public log_type: LogType, public login_name: string = 'default', public is_upload: IsUpload = 0) {
        this.log_type = log_type
        this.id = guid();
        this.url = location.href;
        this.creater_date = new Date().getTime()
        this.count = 1
    }
}
class SiteAnalysis {
    id: string;
    _loginName: string;
    e: any;
    _db: any;
    _prod: boolean;
    _version: string;
    _ip: string;
    _dbType: DBType;
    private _worker;
    public get db() {
        return this._db
    }
    private set db(db) {
        this._db = db
    }
    public get loginName() {
        return this._loginName
    }
    private set loginName(loginName: string) {
        this._loginName = loginName
    }
    private _emitter = new EventEmitter()
    private $upLoadSubction: Subscription;
    constructor(public option: SiteAnalysisOption) {
        // 保证全局单例
        if (window[SINGLE_NAME]) {
            return window[SINGLE_NAME]
        } else {
            this.id = 'ac' + guid()
            this._prod = this.option.production
            this._version = version
            if (!option || !option.siteAnalysisServer) {
                setTimeout(() => {
                    this._emitter.emit(SAEvents.ERROR, 'siteAnalysisServer必传')
                }, 0)
            } else {
                this.option = createDefaultOption(option)
                this.e = {
                    onPageChange: this._onPageChange.bind(this),
                    onUserLogin: this._onUserLogin.bind(this),
                };
                this._worker = new Worker();
                this._worker.onmessage = this.onWorker
                this.getIPbyFront() // 前端获取ip
                this._prod && this.init()
            }
            window.jxstjh_siteAnalysis = this;
        }
    }
    private init() {
        const { appId } = this.option
        if (window.openDatabase) {
            this.db = window.openDatabase('SA' + appId, '1.0', 'JXSTJH_SITE_ANALYSIS', 48 * 1024 * 1024);
            this._dbType = 'webSQL'
            INIT_LOG_TABLE_WEBSQL(this.db).catch(err => {
                this._emitter.emit(SAEvents.ERROR, err)
            }).then(() => {
                this.insetLogMsg(LogType.PAGE).catch(err => {
                    this._emitter.emit(SAEvents.ERROR, err)
                })
            })
        } else if (window.indexedDB) {
            OPEN_DB_AND_INIT('SA' + appId).then((e) => {
                console.log('-OPEN_DB_AND_INIT-', e)
                this.db = e.target.result
                this._dbType = 'indexDB'
                return true
            }).then(() => {
                this.insetLogMsg(LogType.PAGE)
            })
        } else {
            setTimeout(() => {
                this._emitter.emit(SAEvents.ERROR, '不支持webSQL')
                print('JH_SA', '不支持webSQL!', 'error')
            }, 0)
        }
        if (false) {
            // TODO 升级逻辑
            DROP_TABLE(this.db, 'LOG_TABLE')
        }
        this.$upLoadSubction = interval(this.option.interval * 1000).pipe(filter(() => (!!this.db && this._prod))).subscribe(() => {
            this.sqlUnLoadLog()
                .then(row => this.upLoadLog(row))
                .catch(() => { })
        })
    }
    private getIPbyFront() {
        const id = 'sohuIp'
        if (document.getElementById(id)) {
            return
        }
        const s = document.createElement('script')
        s.id = id
        s.src = window.location.protocol + '//pv.sohu.com/cityjson?ie=utf-8'
        s.onload = () => {
            this._ip = window.returnCitySN && window.returnCitySN.cip
        }
        document.body.appendChild(s)
    }
    public setLoginName(loginName: string) {
        this.loginName = loginName
        if (this._prod) {
            return this._onUserLogin()
        } else {
            return Promise.resolve('recordPage in production only')
        }
    }
    private _onPageChange() {
        this.insetLogMsg(LogType.PAGE)
    }
    private _onUserLogin() {
        return new Promise((reslove, reject) => {
            const logItem = new LogItem(LogType.LOGIN, this.loginName, 0)
            if (IS_LOCAL(logItem.url) && !this.option.production) {
                reslove('本地环境')
                return
            }
            if (this._dbType === 'webSQL') {
                const sqlstr = `INSERT INTO LOG_TABLE (id, url, login_name, creater_date, log_type, count, is_upload) VALUES ('${logItem.id}','${logItem.url}','${logItem.login_name}','${logItem.creater_date}',${logItem.log_type},${logItem.count},${logItem.is_upload})`
                crudFromTable(this.db, sqlstr).then(() => {
                    reslove('插入数据成功!')
                }).catch(err => {
                    reject(err)
                })
            } else if (this._dbType === 'indexDB') {
                ADD_ITEM_DB(this.db, logItem).then(e => {
                    reslove(e)
                }).catch(err => {
                    reject(err)
                })
            }
        })
    }
    public recordPage() {
        if (this._prod) {
            return this.insetLogMsg(LogType.PAGE)
        } else {
            return Promise.resolve('recordPage in production only')
        }
    }
    private insetLogMsg(logType: LogType) {
        return new Promise((reslove, reject) => {
            const logItem = new LogItem(logType, this.loginName, 0)
            if (IS_LOCAL(logItem.url) && !this.option.production) {
                reslove('本地环境')
                return
            }
            if (this._dbType === 'webSQL') {
                const sqlstr = `INSERT INTO LOG_TABLE (id, url, login_name, creater_date, log_type, count, is_upload) VALUES ('${logItem.id}','${logItem.url}','${logItem.login_name}','${logItem.creater_date}',${logItem.log_type},${logItem.count},${logItem.is_upload})`
                crudFromTable(this.db, sqlstr).then(() => {
                    reslove('插入数据成功!')
                }).catch(err => {
                    reject(err)
                })
            } else if (this._dbType === 'indexDB') {
                ADD_ITEM_DB(this.db, logItem).then(e => {
                    reslove(e)
                }).catch(err => {
                    reject(err)
                })
            }
        })
    }
    private sqlUnLoadLog = () => {
        if (this._dbType === 'webSQL') {
            return new Promise((reslove, reject) => {
                const sqlStr = 'SELECT * FROM LOG_TABLE WHERE is_upload=0'
                crudFromTable(this.db, sqlStr).then((res) => {
                    const _res = Array.prototype.slice.call(res.rows)
                    if (Array.isArray(_res) && _res.length > 0) {
                        reslove(_res)
                    } else {
                        reject([])
                    }
                }).catch(err => {
                    reject(err)
                })
            })
        } else if (this._dbType === 'indexDB') {
            return new Promise((reslove, reject) => {
                GET_ALL_ITEM(this.db).then(row => {
                    reslove(row)
                }).catch(err => {
                    reject(err)
                })
            })
        }
    }
    private clearUploaded = () => {
        return new Promise((reslove, reject) => {
            const sqlStr = 'DELETE  FROM LOG_TABLE WHERE is_upload=1'
            crudFromTable(this.db, sqlStr).then((res) => {
                const _res = Array.prototype.slice.call(res.rows)
                if (Array.isArray(_res)) {
                    reslove(_res)
                } else {
                    reslove([])
                }
            }).catch(err => {
                reject(err)
            })
        })
    }
    private upLoadLog(row) {
        return new Promise((reslove) => {
            const appId = this.option.appId
            if (Array.isArray(row) && row.length > 0) {
                this._worker.postMessage({ cmd: 'UPLOADLOGLIST', url: this.option.siteAnalysisServer, log: row, appId, ip: this._ip });
                reslove(true)
            }
        })
    }
    private onWorker = (e) => {
        switch (e.data.cmd) {
            case 'UPLOAD_SUCCESS':
                const ids = e.data.ids
                this.upLoaderServerSuccess(ids)
                break;
            default:
                break;
        }
    }
    private upLoaderServerSuccess(ids) {
        print('JH_SA', 'upLoaderServerSuccess!', 'success')
        if (this._dbType === 'webSQL') {
            return new Promise((reslove, reject) => {
                if (ids.length < 1) {
                    reject('length 0')
                }
                let sqlStr = `DELETE FROM LOG_TABLE WHERE id in (`
                ids.forEach((id, index) => {
                    if (index === ids.length - 1) {
                        sqlStr += `'${id}'`
                    } else {
                        sqlStr += `'${id}',`
                    }
                });
                sqlStr += ')'
                crudFromTable(this.db, sqlStr).then(() => {
                    reslove(true)
                }).catch(err => {
                    reject(err)
                })
            })
        } else if (this._dbType === 'indexDB') {
            if (Array.isArray(ids) && ids.length > 0) {
                ids.forEach(id => DEL_ITEM_BYID(this.db, id))
            }
        }
    }
    on(event, listener) {
        this._emitter.addListener(event, listener);
    }
    destroy() {
        this.e = null;
        this._emitter.removeAllListeners();
        this.$upLoadSubction.unsubscribe()
        this._emitter = null;
    }
}
export { SiteAnalysis }